package cn.tedu.charging.order.service.impl;

import cn.tedu.charging.common.pojo.entity.ChargingProgressEsPO;
import cn.tedu.charging.common.pojo.message.ChargingCheckResultMessage;
import cn.tedu.charging.common.pojo.message.ChargingProgressMsg;
import cn.tedu.charging.common.pojo.message.DelayCheckMessage;
import cn.tedu.charging.common.pojo.message.ProgressData;
import cn.tedu.charging.common.pojo.param.ProgressCostParam;
import cn.tedu.charging.common.pojo.po.ChargingBillFailPO;
import cn.tedu.charging.common.pojo.po.ChargingBillSuccessPO;
import cn.tedu.charging.common.pojo.vo.ProgressCostVO;
import cn.tedu.charging.common.protocol.JsonResult;
import cn.tedu.charging.common.protocol.WebSocketMessage;
import cn.tedu.charging.common.utils.SnowflakeIdGenerator;
import cn.tedu.charging.common.utils.TimeConverterUtil;
import cn.tedu.charging.order.client.CostClient;
import cn.tedu.charging.order.client.DeviceClient;
import cn.tedu.charging.order.points.WsServerPoint;
import cn.tedu.charging.order.repository.BillRepository;
import cn.tedu.charging.order.repository.ChargingProgressEsRepository;
import cn.tedu.charging.order.service.ConsumerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
@Slf4j
public class ConsumerServiceImpl implements ConsumerService {
    @Autowired
    private BillRepository billRepository;
    @Autowired
    private DeviceClient deviceClient;
    @Autowired
    private WsServerPoint wsServerPoint;
    @Autowired
    private CostClient costClient;
    private static final SnowflakeIdGenerator generator=new SnowflakeIdGenerator();
    @Autowired
    private ChargingProgressEsRepository chargingProgressEsRepository;
    @Override
    public void handleCheckResult(ChargingCheckResultMessage message) {
        log.debug("收到设备自检结果消息:{}",message);
        //1.使用订单编号 查询订单是否存在
        Boolean exists = checkBillExists(message.getOrderNo());
        //判断 已经存在则不做操作,不存在则正常执行
        if (!exists) {
            Boolean result = message.getResult();
            if (result) {
                log.debug("设备自检成功");
                handleBillSuccess(message);
            } else {
                log.debug("设备自检失败");
                handleBillFail(message);
            }
        }
    }

    @Override
    public void handleDelayCheck(DelayCheckMessage message) {
        log.debug("收到延迟检查结果消息:{}",message);
        //1.拿到订单编号
        String billId = message.getOrderNo();
        //2.检查订单是否已经存在
        Boolean exists=checkBillExists(billId);
        if (!exists) {
            log.debug("订单不存在,按照失败处理");
            ChargingCheckResultMessage checkMessage = new ChargingCheckResultMessage();
            BeanUtils.copyProperties(message, checkMessage);
            checkMessage.setFailDesc("设备自检无响应");
            handleBillFail(checkMessage);
        }
    }

    @Override
    public void handleChargingProgress(ChargingProgressMsg msg) {
        log.debug("收到充电进度消息:{}",msg);
        //1.检查设备参数 以及设备状态是否正常
        Boolean deviceOk=checkDeviceAlarm(msg);
        //2.计算价格 按照和计价中心的接口功能设计这个调用
        ProgressCostVO costVO=calculateCost(msg);
        //3.查询该用户的所剩余额
        Double balance=getUserBalance(msg.getUserId());
        //4.存储充电进度 chargingProgressPO 写入es
        persistProgressPO(msg,costVO.getTotalCost());
        //5.根据上述代码执行结果的某些条件,选择给用户推送什么消息
        WebSocketMessage webSocketMessage=new WebSocketMessage<>();
        if (!deviceOk){
            //5.1设备检查 温度 电压 电流不安全 设备状态不正常 通知用户异常,结账走人 state=1
            webSocketMessage.setState(1);
            webSocketMessage.setMessage("ok");
            webSocketMessage.setData("您的订单,编号:"+msg.getOrderNo()+"设备异常,请结账走人");
        }else if (balance<costVO.getTotalCost()){
            //5.2设备没问题 但是钱不够了 通知用户 异常,结账走人,state=2
            webSocketMessage.setState(2);
            webSocketMessage.setMessage("ok");
            webSocketMessage.setData("您的订单,编号:"+msg.getOrderNo()+"余额不足,请结账走人");
        }else if(msg.getIsFull()){
            //5.3设备没问题,钱也够,充电已经完成,正常结束订单,通知用户结账走人 state没有设计充满的效果
            webSocketMessage.setState(1);
            webSocketMessage.setMessage("ok");
            webSocketMessage.setData("您的订单,编号:"+msg.getOrderNo()+"已经充满结束,请结账走人");
        }else{
            //5.4设备没问题,钱也够,充电没完成,告知用户 本次充电同步的进度信息.20% 30% 40%...
            ProgressData messageData=assembleProgressData(msg,costVO);
            webSocketMessage.setState(3);//充电进度同步一定要=3
            webSocketMessage.setMessage("ok");
            webSocketMessage.setData(messageData);
        }
        wsServerPoint.sendMsg2User(msg.getUserId(),webSocketMessage);
        //UNDO 根据上述推送消息判断订单的结束情况 按照异常结束,和充满正常结束,填补订单的数据success
    }

    private ProgressData assembleProgressData(ChargingProgressMsg msg, ProgressCostVO costVO) {
        //1.准备一个ProgressData
        ProgressData data=new ProgressData();
        data.setTotalCapacity(msg.getTotalCapacity());
        data.setChargingCapacity(costVO.getChargingCapacity());
        data.setOneElectricityCost(costVO.getPowerFee());
        data.setTotalCost(costVO.getTotalCost());
        Long totalTime = msg.getTotalTime();//毫秒数 充电总时长 小时 分钟 秒
        data.setHours(TimeConverterUtil.getHour(totalTime).intValue());
        data.setMinutes(TimeConverterUtil.getMinute(totalTime).intValue());
        data.setSeconds(TimeConverterUtil.getSecond(totalTime).intValue());
        return data;
    }

    private void persistProgressPO(ChargingProgressMsg msg, Double totalCost) {
        //1.组织一个PO对象 作为es存储的持久化数据封装
        ChargingProgressEsPO esPo=new ChargingProgressEsPO();
        BeanUtils.copyProperties(msg,esPo);
        //应该保证id是递增的 有序的 且唯一的 雪花算法更合适 id在es中不可以为空 如果为空 自动补充随机字符串
        esPo.setId(generator.nextId()+"");
        esPo.setTemperature(totalCost);
        //2.创建一个repository数据层
        //3.调用save方法
        chargingProgressEsRepository.save(esPo);
    }

    private Double getUserBalance(Integer userId) {
        log.debug("查询用户余额,用户id:{}",userId);
        return 999999.99;
    }

    private ProgressCostVO calculateCost(ChargingProgressMsg msg) {
        //1.组织ProgressCostParam
        ProgressCostParam param=new ProgressCostParam();
        BeanUtils.copyProperties(msg,param);
        //2.调用接口获取结果
        JsonResult<ProgressCostVO> result = costClient.calculateBill(param);
        if (result.getCode()==0){
            return result.getData();
        }else{
            throw new RuntimeException("调用计费接口失败");
        }
    }

    private Boolean checkDeviceAlarm(ChargingProgressMsg msg) {
        log.debug("当前设备温度:{},设备电压:{},设备电流:{}",msg.getTemperature(),null,null);
        log.debug("经过检查 设备正常");
        return true;
    }

    private Boolean checkBillExists(String billId) {
        //1.查询success的存在 exists
        Long successCount=billRepository.countSuccess(billId);
        //2.查询fail的存在 exists
        Long failCount=billRepository.countFail(billId);
        return successCount>0||failCount>0;
    }

    private void handleBillFail(ChargingCheckResultMessage message) {
        //1.组织失败,写入数据库
        ChargingBillFailPO fail=new ChargingBillFailPO();
        fail.setBillId(message.getOrderNo());
        fail.setUserId(message.getUserId());
        fail.setGunId(message.getGunId());
        fail.setFailDesc(message.getFailDesc());
        fail.setCreateTime(new Date());
        fail.setUpdateTime(fail.getCreateTime());
        fail.setDeleted(0);
        billRepository.saveBillFail(fail);
        //2.远程调用修改枪状态为故障 TODO
        //3.1组织一个数据消息对象
        WebSocketMessage<String> msg=new WebSocketMessage<>();
        msg.setState(1);
        msg.setMessage(fail.getFailDesc());
        msg.setData("您的订单,编号:"+message.getOrderNo()+"已经失败.请查找原因");
        //3.2如果用户在线,可以找到用户,将消息推送到前台客户端
        wsServerPoint.sendMsg2User(message.getUserId(),msg);
    }

    private void handleBillSuccess(ChargingCheckResultMessage message) {
        //1.组织成功对象,写入数据库
        ChargingBillSuccessPO success=new ChargingBillSuccessPO();
        //能封装的属性全封装,参数有就直接用,没有一定可以查询到
        success.setBillId(message.getOrderNo());
        success.setUserId(message.getUserId());
        success.setGunId(message.getGunId());
        success.setBillStatus(1);//状态一般都是枚举 1充电中 2充电正常结束 3充电异常 4欠费 5...
        success.setCreateTime(new Date());
        success.setChargingStartTime(success.getCreateTime());
        success.setUpdateTime(success.getCreateTime());
        success.setDeleted(0);//逻辑删除 0表示未删除
        billRepository.saveBillSuccess(success);
        //2.给用户发送通知 你的订单马上开始充电 发送成功消息
        //2.1组织一个数据消息对象
        WebSocketMessage<String> msg=new WebSocketMessage<>();
        msg.setState(1);
        msg.setMessage("您的订单马上开始充电");
        msg.setData("您的订单,编号:"+message.getOrderNo()+"马上就要开始充电了");
        //2.2如果用户在线,可以找到用户,将消息推送到前台客户端
        wsServerPoint.sendMsg2User(message.getUserId(),msg);
    }
}
